<template>
    <canvas ref="canvas" class="canvas" ></canvas>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { createFramebuffer, createShader, createTexture } from './gl'
const imgList = ['/img/333.jpg', '/img/ccs.jpg']
const canvas = ref()
const video = ref()
const isLogin = ref(true)
let renderer, renderId
let scene
let camera, geom, textureLoader, uniform, clock, composer
let width, height
let gl, vertexShader, fragmentShader, program
let effectTarget, effectFrame
let oldTime = 0, time = 0
const image = new Image()
const vs = `#version 300 es
  // attribute vec3 aPos;
  in vec3 aPos;

  in vec2 uv;
  out highp vec2 vUv;

  // varying highp vec2 vUv;
  void main(void){
    gl_Position = vec4(aPos, 1);
    vUv = uv;
  }
`
const Effs = `
  varying highp vec2 vUv;
  uniform sampler2D map;
  void main(void) {
    // gl_FragColor = texture2D(map, vUv) + vec4(sin(iTime),0.,0., 1.0) * 0.5;
    gl_FragColor =  vec4(sin(iTime),0.,0., 1.0);
  }
`
const Effect = {
  program: null,
  vertexShader: null,
  // 片元着色器
  fragmentShader: null,
  init() {
    this.program = gl.createProgram()
    this.vertexShader = createShader(gl, vs, gl.VERTEX_SHADER)
    this.fragmentShader = createShader(gl, Effs, gl.FRAGMENT_SHADER)
    const vertexBuffer = gl.createBuffer()
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertex), gl.STATIC_DRAW)

    const vertexIndiceBuffer = gl.createBuffer()
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndiceBuffer)
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(vertexIndice), gl.STATIC_DRAW)

    const aVertexPosition = gl.getAttribLocation(program, 'aPos')
    gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0)
    gl.enableVertexAttribArray(aVertexPosition)
    // 设置 texCoords
    // 创建缓冲1区
    const trianglesTexCoordBuffer = gl.createBuffer()
    gl.bindBuffer(gl.ARRAY_BUFFER, trianglesTexCoordBuffer)
    // 绑定数据
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW)
    // 获取 attrib
    const vertexTexCoordAttribute = gl.getAttribLocation(program, 'uv')
    gl.enableVertexAttribArray(vertexTexCoordAttribute) // 开启
    // 设置值
    gl.vertexAttribPointer(vertexTexCoordAttribute, 2, gl.FLOAT, false, 0, 0)
  },
}
// 矩形的坐标
const vertex = [
  -1, 1, 0.0, // 上
  1, 1, 0.0, // 右
  1, -1, 0.0, // 下
  -1, -1, 0.0, // 左
]

const vertexIndice = [
  0, 1, 2,
  0, 2, 3,
]

const texCoords = [
  0.0, 0.0, // position[0] 对应的uv坐标
  1.0, 0.0, // position[1] 对应的uv坐标
  1.0, 1.0, // position[2] 对应的uv坐标
  0.0, 1.0, // position[3] 对应的uv坐标
]

const buffers = {}
const uniforms = {}
function addMesh(gl, program) {
  buffers.vertexBuffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, buffers.vertexBuffer)
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertex), gl.STATIC_DRAW)

  buffers.vertexIndiceBuffer = gl.createBuffer()
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.vertexIndiceBuffer)
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(vertexIndice), gl.STATIC_DRAW)

  const aVertexPosition = gl.getAttribLocation(program, 'aPos')
  gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0)
  gl.enableVertexAttribArray(aVertexPosition)
  // 设置 texCoords
  // 创建缓冲1区
  buffers.trianglesTexCoordBuffer = gl.createBuffer()
  gl.bindBuffer(gl.ARRAY_BUFFER, buffers.trianglesTexCoordBuffer)
  // 绑定数据
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW)
  // 获取 attrib
  const vertexTexCoordAttribute = gl.getAttribLocation(program, 'uv')
  gl.enableVertexAttribArray(vertexTexCoordAttribute) // 开启
  // 设置值
  gl.vertexAttribPointer(vertexTexCoordAttribute, 2, gl.FLOAT, false, 0, 0)
}
function createMatShader() {
  // 定点着色器
  if (!vertexShader)vertexShader = createShader(gl, vs, gl.VERTEX_SHADER)
  const ss = `#version 300 es
  precision highp float;
precision highp int;
precision mediump sampler2D;
uniform vec3 iResolution;
uniform vec3 iMouse;
uniform float iTime;
uniform sampler2D  map;
in vec2 vUv;
#define S(a, b, t) smoothstep(a, b, t)
//#define CHEAP_NORMALS
#define HAS_HEART
out vec4 FragColor;
#define USE_POST_PROCESSING

vec3 N13(float p) {
    //  from DAVE HOSKINS
   vec3 p3 = fract(vec3(p) * vec3(.1031,.11369,.13787));
   p3 += dot(p3, p3.yzx + 19.19);
   return fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
}
vec4 N14(float t) {
return fract(sin(t*vec4(123., 1024., 1456., 264.))*vec4(6547., 345., 8799., 1564.));
}
float N(float t) {
    return fract(sin(t*12345.564)*7658.76);
}
float Saw(float b, float t) {
return S(0., b, t)*S(1., b, t);
}
vec2 DropLayer2(vec2 uv, float t) {
    vec2 UV = uv;
    uv.y += t*0.75;
    vec2 a = vec2(6., 1.);
    vec2 grid = a*2.;
    vec2 id = floor(uv*grid);
    float colShift = N(id.x);
    uv.y += colShift;
    id = floor(uv*grid);
    vec3 n = N13(id.x*35.2+id.y*2376.1);
    vec2 st = fract(uv*grid)-vec2(.5, 0);
    float x = n.x-.5;
    float y = UV.y*20.;
    float wiggle = sin(y+sin(y));
    x += wiggle*(.5-abs(x))*(n.z-.5);
    x *= .7;
    float ti = fract(t+n.z);
    y = (Saw(.85, ti)-.5)*.9+.5;
    vec2 p = vec2(x, y);
    float d = length((st-p)*a.yx);
    float mainDrop = S(.4, .0, d);
    float r = sqrt(S(1., y, st.y));
    float cd = abs(st.x-x);
    float trail = S(.23*r, .15*r*r, cd);
    float trailFront = S(-.02, .02, st.y-y);
    trail *= trailFront*r*r;
    y = UV.y;
    float trail2 = S(.2*r, .0, cd);
    float droplets = max(0., (sin(y*(1.-y)*120.)-st.y))*trail2*trailFront*n.z;
    y = fract(y*10.)+(st.y-.5);
    float dd = length(st-vec2(x, y));
    droplets = S(.3, 0., dd);
    float m = mainDrop+droplets*r*trailFront;
    //m += st.x>a.y*.45 || st.y>a.x*.165 ? 1.2 : 0.;
    return vec2(m, trail);
}

float StaticDrops(vec2 uv, float t) {
    uv *= 40.;
    vec2 id = floor(uv);
    uv = fract(uv)-.5;
    vec3 n = N13(id.x*107.45+id.y*3543.654);
    vec2 p = (n.xy-.5)*.7;
    float d = length(uv-p);
    float fade = Saw(.025, fract(t+n.z));
    float c = S(.3, 0., d)*fract(n.z*10.)*fade;
    return c;
}

vec2 Drops(vec2 uv, float t, float l0, float l1, float l2) {
    float s = StaticDrops(uv, t)*l0;
    vec2 m1 = DropLayer2(uv, t)*l1;
    vec2 m2 = DropLayer2(uv*1.85, t)*l2;
    float c = s+m1.x+m2.x;
    c = S(.3, 1., c);
    return vec2(c, max(m1.y*l0, m2.y*l1));
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{

    vec2 uv = (fragCoord.xy-.5*iResolution.xy) / iResolution.y;
    vec2 UV = fragCoord.xy/iResolution.xy;
    vec3 M = iMouse.xyz/iResolution.xyz;
    float T = iTime+M.x*2.;
    #ifdef HAS_HEART
    T = mod(iTime, 102.);
    T = mix(T, M.x*102., M.z>0.?1.:0.);
    #endif
    float t = T*.2;
    float rainAmount = iMouse.z>0. ? M.y : sin(T*.05)*.3+.7;
    float maxBlur = mix(3., 6., rainAmount);
    float minBlur = 2.;
    float story = 0.;
    float heart = 0.;
    #ifdef HAS_HEART
    story = S(0., 70., T);

    t = min(1., T/70.);  // remap drop time so it goes slower when it freezes
    t = 1.-t;
    t = (1.-t*t)*70.;

    float zoom= mix(.3, 1.2, story); // slowly zoom out
    uv *=zoom;
    minBlur = 4.+S(.5, 1., story)*3.; // more opaque glass towards the end
    maxBlur = 6.+S(.5, 1., story)*1.5;

    vec2 hv = uv-vec2(.0, -.1); // build heart
    hv.x *= .5;
    float s = S(110., 70., T); // heart gets smaller and fades towards the end
    hv.y-=sqrt(abs(hv.x))*.5*s;
    heart = length(hv);
    heart = S(.4*s, .2*s, heart)*s;
    rainAmount = heart; // the rain is where the heart is

    maxBlur-=heart; // inside the heart slighly less foggy
    uv *= 1.5; // zoom out a bit more
    t *= .25;
    #else
    float zoom = -cos(T*.2);
    uv *= .7+zoom*.3;
    #endif
      UV = (UV-.5)*(.9+zoom*.1)+.5;

    float staticDrops = S(-.5, 1., rainAmount)*2.;
    float layer1 = S(.25, .75, rainAmount);
    float layer2 = S(.0, .5, rainAmount);


    vec2 c = Drops(uv, t, staticDrops, layer1, layer2);
   #ifdef CHEAP_NORMALS
    \tvec2 n = vec2(dFdx(c.x), dFdy(c.x));// cheap normals (3x cheaper, but 2 times shittier ;))
    #else
    \tvec2 e = vec2(.001, 0.);
    \tfloat cx = Drops(uv+e, t, staticDrops, layer1, layer2).x;
    \tfloat cy = Drops(uv+e.yx, t, staticDrops, layer1, layer2).x;
    \tvec2 n = vec2(cx-c.x, cy-c.x);\t\t// expensive normals
    #endif
    #ifdef HAS_HEART
    n *= 1.-S(60., 85., T);
    c.y *= 1.-S(80., 100., T)*.8;
    #endif
    float focus = mix(maxBlur-c.y, minBlur, S(.1, .2, c.x));
    vec3 col = textureLod(map, UV+n, focus).rgb;
    #ifdef USE_POST_PROCESSING
    t = (T+3.)*.5;\t\t\t\t\t\t\t\t\t\t// make time sync with first lightnoing
    float colFade = sin(t*.2)*.5+.5+story;
    col *= mix(vec3(1.), vec3(.8, .9, 1.3), colFade);\t// subtle color shift
    float fade = S(0., 10., T);\t\t\t\t\t\t\t// fade in at the start
    float lightning = sin(t*sin(t*10.));\t\t\t\t// lighting flicker
    lightning *= pow(max(0., sin(t+sin(t))), 10.);\t\t// lightning flash
    col *= 1.+lightning*fade*mix(1., .1, story*story);\t// composite lightning
    col *= 1.-dot(UV-=.5, UV);\t\t\t\t\t\t\t// vignette
    #ifdef HAS_HEART
    \tcol = mix(pow(col, vec3(1.2)), col, heart);
    \tfade *= S(102., 97., T);
    #endif

    col *= fade;\t\t\t\t\t\t\t\t\t\t// composite start and end fade
    #endif
    //col = vec3(heart);
    fragColor = vec4(col, 1.);
    // fragColor = textureLod(map, uv,1.);
    // fragColor = vec4(focus/10.,0.,0., 1.);
}
  void main() {
          mainImage(FragColor,gl_FragCoord.xy);
        }
  `
  // 片元着色器
  if (!fragmentShader)fragmentShader = createShader(gl, ss, gl.FRAGMENT_SHADER)
  gl.attachShader(program, vertexShader)
  gl.attachShader(program, fragmentShader)
  gl.linkProgram(program)
  gl.useProgram(program)
  uniforms.iResolution = gl.getUniformLocation(program, 'iResolution')
  uniforms.iMouse = gl.getUniformLocation(program, 'iMouse')
  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    console.error('Unable to initialize the shader program.')
  }
}
function render() {
  clear()
  const now = new Date().getTime()
  if (oldTime) {
    time += (now - oldTime) / 1000
  }
  oldTime = now
  gl.uniform1f(uniforms.time, time)
  // // 设置 uSampler
  // gl.uniform1i(uniforms.samplerUniform, 0)
  // gl.bindTexture(gl.TEXTURE_2D, uniforms.texture)
  // if (video.value.loaded === true) {
  //   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, video.value.width, video.value.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, video.value)
  //   gl.generateMipmap(gl.TEXTURE_2D) // texImage2D 之后必须执行不然没有Mipmap
  // }
  gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0)
}
function clear() {
  gl.clearColor(0.0, 0.0, 0.0, 1.0)
  gl.clear(gl.COLOR_BUFFER_BIT)
}
function initGl(canvas, width, height) {
  gl = canvas.getContext('webgl2')
  if (!gl) {
    console.error('Unable to get webgl context.')
    return
  }
  // console.log(gl)
  program = gl.createProgram()
  // effectTarget = createTexture(gl, width, height)
  // effectFrame = createFramebuffer(gl, effectTarget)
  window.onresize = () => {
    setSize(gl, window.innerWidth, window.innerHeight)
  }
  // setSize(gl, width, height)
  return gl
}
function setSize(gl, width, height) {
  const pixelRatio = window.devicePixelRatio
  const widthR = pixelRatio * width
  const heightR = pixelRatio * height
  gl.canvas.width = widthR
  gl.canvas.height = heightR
  gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight)
  gl.uniform3fv(uniforms.iResolution, [widthR, heightR, 0])
  gl.uniform3fv(uniforms.iMouse, [0, 0, 0])
}
function init() {
  const container = canvas.value // document.getElementById('container')
  initGl(container, window.innerWidth, window.innerHeight)
  createMatShader()
  addMesh(gl, program)
  uniforms.texture = createTexture(gl, width, height)
  gl.bindTexture(gl.TEXTURE_2D, uniforms.texture)
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true) // 翻转Y轴
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
  // 获取 uSampler
  uniforms.samplerUniform = gl.getUniformLocation(program, 'map')
  uniforms.time = gl.getUniformLocation(program, 'iTime')
  gl.uniform1f(uniforms.time, time)
  // 设置 uSampler
  gl.uniform1i(uniforms.samplerUniform, 0)
  // gl.bindTexture(gl.TEXTURE_2D, uniforms.texture)
  setSize(gl, window.innerWidth, window.innerHeight)
  window.addEventListener('mousedown', e => {
    gl.uniform3fv(uniforms.iMouse, [e.clientX, e.clientY, 1])
  })
  window.addEventListener('mouseup', e => {
    gl.uniform3fv(uniforms.iMouse, [e.clientX, e.clientY, 0])
  })
  image.src = imgList[new Date().getDay() % 2]
  image.addEventListener('load', () => {
    gl.bindTexture(gl.TEXTURE_2D, uniforms.texture)
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, image.width, image.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, image)
    gl.generateMipmap(gl.TEXTURE_2D) // texImage2D 之后必须执行不然没有Mipmap
    animate()
  }, false)
}
const animate = () => {
  renderId = requestAnimationFrame(animate)
  render()
}
onBeforeUnmount(() => {
  cancelAnimationFrame(renderId)
  gl.deleteProgram(program)
  gl.deleteShader(vertexShader)
  gl.deleteShader(fragmentShader)
  for (const key in buffers) {
    gl.deleteBuffer(buffers[key])
  }
})
onMounted(() => {
  init()
})

</script>

<style lang="scss" scoped>
.canvas {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
}

</style>
